const fs = require('fs-extra');
const path = require('path');
const os = require('os');
const ffmpeg = require('fluent-ffmpeg');
const { spawn } = require('child_process');
const jschardet = require('jschardet');
const iconv = require('iconv-lite');

class VideoProcessor {
    constructor(downloadDir) {
        this.downloadDir = downloadDir;
        this.workflowQueue = new Map();
        this.processingStatus = new Map();
    }

    // 查找文件方法
    async findFileByName(fileName) {
        // 参数验证
        if (!fileName || typeof fileName !== 'string') {
            console.warn('findFileByName: fileName 参数无效:', fileName);
            return null;
        }

        console.log('正在查找文件:', fileName);

        const searchPaths = [
            this.downloadDir,
            path.join(this.downloadDir, 'processed'),
            path.join(__dirname, '../uploads')
        ];

        // 规范化文件名，处理特殊字符
        const normalizeFileName = (name) => {
            return name
                .replace(/[＊]/g, '*')  // 全角星号转半角
                .replace(/[｜]/g, '|')  // 全角竖线转半角
                .replace(/[：]/g, ':')  // 全角冒号转半角
                .replace(/[？]/g, '?')  // 全角问号转半角
                .replace(/[＜]/g, '<')  // 全角小于号转半角
                .replace(/[＞]/g, '>')  // 全角大于号转半角
                .replace(/[＂]/g, '"')  // 全角双引号转半角
                .replace(/[／]/g, '/')  // 全角斜杠转半角
                .replace(/[＼]/g, '\\') // 全角反斜杠转半角
                .trim();
        };

        const normalizedFileName = normalizeFileName(fileName);
        console.log('规范化后的文件名:', normalizedFileName);

        for (const searchPath of searchPaths) {
            if (await fs.pathExists(searchPath)) {
                console.log('搜索路径:', searchPath);
                const files = await this.findFilesRecursively(searchPath);
                
                // 尝试多种匹配策略
                let found = null;
                
                // 1. 精确匹配（原始文件名）
                found = files.find(file => path.basename(file) === fileName);
                if (found) {
                    console.log('精确匹配找到文件:', found);
                    return found;
                }
                
                // 2. 精确匹配（规范化文件名）
                found = files.find(file => path.basename(file) === normalizedFileName);
                if (found) {
                    console.log('规范化匹配找到文件:', found);
                    return found;
                }
                
                // 3. 包含匹配（忽略大小写）
                found = files.find(file => {
                    const baseName = path.basename(file).toLowerCase();
                    const searchName = fileName.toLowerCase();
                    return baseName.includes(searchName) || searchName.includes(baseName);
                });
                if (found) {
                    console.log('包含匹配找到文件:', found);
                    return found;
                }
                
                // 4. 规范化包含匹配
                found = files.find(file => {
                    const baseName = normalizeFileName(path.basename(file)).toLowerCase();
                    const searchName = normalizedFileName.toLowerCase();
                    return baseName.includes(searchName) || searchName.includes(baseName);
                });
                if (found) {
                    console.log('规范化包含匹配找到文件:', found);
                    return found;
                }
                
                // 5. 去除扩展名匹配
                const fileNameWithoutExt = path.parse(fileName).name;
                found = files.find(file => {
                    const baseNameWithoutExt = path.parse(path.basename(file)).name;
                    return baseNameWithoutExt.toLowerCase().includes(fileNameWithoutExt.toLowerCase()) ||
                           fileNameWithoutExt.toLowerCase().includes(baseNameWithoutExt.toLowerCase());
                });
                if (found) {
                    console.log('去除扩展名匹配找到文件:', found);
                    return found;
                }
            }
        }
        
        console.log('未找到文件:', fileName);
        return null;
    }

    async findFilesRecursively(dir) {
        const files = [];
        const items = await fs.readdir(dir);
        
        for (const item of items) {
            const fullPath = path.join(dir, item);
            const stat = await fs.stat(fullPath);
            
            if (stat.isDirectory()) {
                files.push(...await this.findFilesRecursively(fullPath));
            } else {
                files.push(fullPath);
            }
        }
        
        return files;
    }

    // 检查 FFmpeg 是否可用
    async checkFFmpeg() {
        return new Promise((resolve) => {
            const ffmpegProcess = spawn('ffmpeg', ['-version']);
            ffmpegProcess.on('close', (code) => {
                resolve(code === 0);
            });
            ffmpegProcess.on('error', () => {
                resolve(false);
            });
        });
    }

    // 创建工作流
    async createWorkflow(inputFiles, operations, outputDir) {
        const workflowId = `workflow_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
        
        const workflow = {
            id: workflowId,
            inputFiles,
            operations,
            outputDir,
            status: 'pending',
            createdAt: new Date(),
            results: [],
            finalOutputs: [],
            currentStep: 0
        };

        this.workflowQueue.set(workflowId, workflow);
        this.processingStatus.set(workflowId, { status: 'pending' });
        
        console.log(`创建工作流: ${workflowId}`, { inputFiles, operations });
        return workflowId;
    }

    // 执行工作流
    async executeWorkflow(workflowId, progressCallback = null, serialProcessing = false) {
        const workflow = this.workflowQueue.get(workflowId);
        if (!workflow) {
            throw new Error('工作流不存在');
        }

        workflow.status = 'processing';
        this.processingStatus.set(workflowId, { status: 'processing' });

        try {
            let currentInputs = workflow.inputFiles;
            
            for (let i = 0; i < workflow.operations.length; i++) {
                const operation = workflow.operations[i];
                workflow.currentStep = i + 1;
                
                if (progressCallback) {
                    progressCallback({
                        workflowId,
                        status: 'processing',
                        currentStep: workflow.currentStep,
                        totalSteps: workflow.operations.length,
                        message: `正在执行操作: ${operation.type}`
                    });
                }

                const result = await this.executeOperation(operation, currentInputs, workflow.outputDir, progressCallback, workflowId);
                workflow.results.push(result);
                
                // 更新输入文件为当前操作的输出
                if (result.outputFiles && result.outputFiles.length > 0) {
                    currentInputs = result.outputFiles;
                }
            }

            workflow.finalOutputs = currentInputs;
            workflow.status = 'completed';
            this.processingStatus.set(workflowId, { status: 'completed' });

            if (progressCallback) {
                progressCallback({
                    workflowId,
                    status: 'completed',
                    finalOutputs: workflow.finalOutputs,
                    message: '所有操作已完成'
                });
            }

            return workflow;
        } catch (error) {
            workflow.status = 'failed';
            workflow.error = error.message;
            this.processingStatus.set(workflowId, { status: 'failed', error: error.message });

            if (progressCallback) {
                progressCallback({
                    workflowId,
                    status: 'failed',
                    error: error.message
                });
            }

            throw error;
        }
    }

    // 执行单个操作
    async executeOperation(operation, inputFiles, outputDir, progressCallback, workflowId) {
        const { type, params } = operation;

        switch (type) {
            case 'trim':
                return await this.trimVideo(inputFiles[0], params, outputDir);
            case 'scale':
                return await this.scaleVideo(inputFiles[0], params, outputDir, progressCallback, workflowId);
            case 'watermark':
                return await this.addWatermark(inputFiles[0], params, outputDir);
            case 'merge':
                return await this.mergeVideos(inputFiles, params, outputDir);
            case 'mirror':
                return await this.mirrorVideo(inputFiles[0], params, outputDir);
            case 'rotate':
                return await this.rotateVideo(inputFiles[0], params, outputDir);
            case 'speed':
                return await this.changeSpeed(inputFiles[0], params, outputDir);
            case 'mosaic':
                return await this.addMosaic(inputFiles[0], params, outputDir, progressCallback, workflowId);
            case 'background':
                return await this.addBackgroundImage(inputFiles[0], params, outputDir, progressCallback, workflowId);
            case 'backgroundVideo':
                return await this.addBackgroundVideo(params, outputDir, progressCallback, workflowId);
            case 'subtitle':
                return await this.addSubtitle(inputFiles[0], params, outputDir, progressCallback, workflowId);
            case 'split':
                return await this.splitVideo(inputFiles[0], params, outputDir, progressCallback, workflowId);
            default:
                throw new Error(`不支持的操作类型: ${type}`);
        }
    }

    // 颜色转换函数
    colorToHex(color) {
        const colorMap = {
            'white': 'FFFFFF',
            'black': '000000',
            'red': '0000FF',     // BGR格式：红色
            'green': '00FF00',   // BGR格式：绿色
            'blue': 'FF0000',    // BGR格式：蓝色
            'yellow': '00FFFF',  // BGR格式：黄色
            'cyan': 'FFFF00',    // BGR格式：青色
            'magenta': 'FF00FF', // BGR格式：品红色
            'orange': '0080FF',  // BGR格式：橙色
            'purple': '800080',  // BGR格式：紫色
            'gray': '808080',    // BGR格式：灰色
            'grey': '808080'     // BGR格式：灰色
        };
        
        // 如果是预定义颜色，直接返回BGR值
        if (colorMap[color.toLowerCase()]) {
            return colorMap[color.toLowerCase()];
        }
        
        // 如果是十六进制颜色码
        if (color.startsWith('#')) {
            const hex = color.substring(1);
            if (hex.length === 6) {
                // 将RGB转换为BGR
                const r = hex.substring(0, 2);
                const g = hex.substring(2, 4);
                const b = hex.substring(4, 6);
                return b + g + r; // BGR格式
            }
        }
        
        // 默认返回白色
        return 'FFFFFF';
    }

    // 字幕处理方法
    async addSubtitle(inputFile, params, outputDir, progressCallback, workflowId) {
        const { subtitleFile, fontColor = 'white', fontSize = 20, fontName = 'Arial', displayMode = 'proportional', frequency = 5, skipEmptyLines = true, position = 'bottom' } = params;
        
        // 解析输入文件路径
        const resolvedInputPath = await this.findFileByName(inputFile);
        if (!resolvedInputPath) {
            throw new Error(`找不到输入文件: ${inputFile}`);
        }
    
        const outputFile = path.join(outputDir, `subtitled_${Date.now()}_${path.basename(resolvedInputPath)}`);
    
        // 解析字幕文件路径
        let resolvedSubtitlePath;
        if (path.isAbsolute(subtitleFile)) {
            resolvedSubtitlePath = subtitleFile;
        } else {
            resolvedSubtitlePath = await this.findFileByName(subtitleFile);
            if (!resolvedSubtitlePath) {
                resolvedSubtitlePath = path.join(this.downloadDir, subtitleFile);
            }
        }
    
        if (!await fs.pathExists(resolvedSubtitlePath)) {
            throw new Error(`找不到字幕文件: ${subtitleFile}`);
        }
    
        // 获取视频时长用于调试和后续处理
        const probe = await new Promise((resolve, reject) => {
            ffmpeg.ffprobe(resolvedInputPath, (err, metadata) => {
                if (err) reject(err);
                resolve(metadata);
            });
        });
        const videoDuration = probe.format.duration;

        // 添加调试日志
        console.log('字幕处理参数:', {
            displayMode,
            frequency,
            fontColor,
            fontSize,
            fontName,
            position,
            videoDuration
        });

        // 检测字幕文件编码并转换
        let subtitleContent;
        try {
            const buffer = await fs.readFile(resolvedSubtitlePath);
            const detected = jschardet.detect(buffer);
            console.log('检测到的编码:', detected);
            
            let encoding = 'utf8';
            if (detected && detected.encoding) {
                if (detected.encoding.toLowerCase().includes('gb') || detected.encoding.toLowerCase().includes('gbk')) {
                    encoding = 'gbk';
                } else if (detected.encoding.toLowerCase().includes('utf')) {
                    encoding = 'utf8';
                } else {
                    encoding = detected.encoding;
                }
            }
            
            try {
                subtitleContent = iconv.decode(buffer, encoding);
            } catch (decodeError) {
                console.warn('使用检测编码解码失败，尝试GBK:', decodeError.message);
                try {
                    subtitleContent = iconv.decode(buffer, 'gbk');
                } catch (gbkError) {
                    console.warn('GBK解码失败，使用UTF-8:', gbkError.message);
                    subtitleContent = iconv.decode(buffer, 'utf8');
                }
            }
        } catch (error) {
            console.error('字幕文件读取失败:', error);
            throw new Error(`字幕文件读取失败: ${error.message}`);
        }
    
        // 如果是TXT文件，转换为SRT格式
        if (resolvedSubtitlePath.toLowerCase().endsWith('.txt')) {
            console.log('转换TXT到SRT格式');
            subtitleContent = this.convertTxtToSrt(subtitleContent, videoDuration, displayMode, frequency, skipEmptyLines);
            console.log('转换后的SRT内容预览:', subtitleContent.substring(0, 200));
        }
    
        // 创建临时字幕文件，使用UTF-8编码保存
        const tempSubtitleFile = path.join(outputDir, `temp_subtitle_${Date.now()}.srt`);
        console.log('创建临时字幕文件:', tempSubtitleFile);
        await fs.writeFile(tempSubtitleFile, subtitleContent, { encoding: 'utf8' });
        
        // 验证临时文件是否创建成功
        const tempFileExists = await fs.pathExists(tempSubtitleFile);
        console.log('临时字幕文件是否存在:', tempFileExists);
        if (tempFileExists) {
            const tempFileStats = await fs.stat(tempSubtitleFile);
            console.log('临时字幕文件大小:', tempFileStats.size, 'bytes');
        }
    
        // Windows 路径转义处理
        let ffmpegSubtitlePath = tempSubtitleFile.replace(/\\/g, '/');
        ffmpegSubtitlePath = ffmpegSubtitlePath.replace(/^([a-zA-Z]):/, '$1\:');
        
        // 构建字幕滤镜字符串，添加换行支持和位置控制
        let alignment = 2; // 默认底部
        let marginV = 20;
        
        // 根据位置参数设置对齐方式和边距
        switch (position) {
            case 'top':
                alignment = 8; // 顶部居中
                marginV = 20;
                break;
            case 'center':
                alignment = 5; // 中间居中
                marginV = 0;
                break;
            case 'bottom':
            default:
                alignment = 2; // 底部居中
                marginV = 20;
                break;
        }
        
        // 检测是否包含中文字符
        const isChineseContent = /[\u4e00-\u9fff]/.test(subtitleContent);
        
        // 设置换行样式：中文使用0（智能换行），其他语言使用1（行尾换行）
        const wrapStyle = isChineseContent ? 0 : 1;
        
        // 设置左右边距，防止字幕超出屏幕边界
        const marginL = 50;  // 左边距
        const marginR = 50;  // 右边距
        
        const subtitlesFilter = `subtitles='${ffmpegSubtitlePath.replace(/:/g, '\\:').replace(/'/g, "\\'")}':force_style='PrimaryColour=&H00${this.colorToHex(fontColor)}&,FontSize=${fontSize},FontName=${fontName},WrapStyle=${wrapStyle},Alignment=${alignment},MarginV=${marginV},MarginL=${marginL},MarginR=${marginR}'`;
        
        console.log('输出文件路径:', outputFile);

        return new Promise((resolve, reject) => {
            const command = ffmpeg(resolvedInputPath)
                .videoFilters(subtitlesFilter)
                .outputOptions(['-c:v', 'libx264', '-c:a', 'copy', '-avoid_negative_ts', 'make_zero'])
                .output(outputFile);
                
            console.log('FFmpeg命令构建完成，开始执行...');
    
            command.on('start', (cmdLine) => {
                console.log('FFmpeg命令行:', cmdLine);
            });

            command.on('progress', (progress) => {
                console.log('FFmpeg进度:', progress);
                if (progressCallback) {
                    progressCallback({
                        status: 'processing',
                        message: `字幕处理进度: ${progress.percent ? progress.percent.toFixed(1) + '%' : '处理中...'}`,
                        percent: progress.percent || 0,
                        timemark: progress.timemark,
                        currentFps: progress.currentFps,
                        targetSize: progress.targetSize,
                        currentKbps: progress.currentKbps
                    });
                }
            });

            command.on('end', async () => {
                console.log('FFmpeg处理完成');
                // 清理临时字幕文件
                try {
                    await fs.remove(tempSubtitleFile);
                    console.log('临时字幕文件已清理');
                } catch (cleanupError) {
                    console.warn('清理临时字幕文件失败:', cleanupError.message);
                }
                
                resolve({
                    type: 'subtitle',
                    inputFiles: [resolvedInputPath],
                    outputFiles: [outputFile],
                    params
                });
            });

            command.on('error', (error) => {
                console.error('FFmpeg错误:', error);
                reject(error);
            });

            command.run();
        });
    }

    // 其他视频处理方法的实现...
    async trimVideo(inputFile, params, outputDir) {
        const { startTime, endTime } = params;
        const resolvedPath = await this.findFileByName(inputFile);
        if (!resolvedPath) {
            throw new Error(`找不到输入文件: ${inputFile}`);
        }
        
        const outputFile = path.join(outputDir, `trimmed_${Date.now()}_${path.basename(resolvedPath)}`);

        return new Promise((resolve, reject) => {
            ffmpeg(resolvedPath)
                .seekInput(startTime)
                .duration(this.calculateDuration(startTime, endTime))
                .output(outputFile)
                .on('end', () => {
                    resolve({
                        type: 'trim',
                        inputFiles: [resolvedPath],
                        outputFiles: [outputFile],
                        params
                    });
                })
                .on('error', reject)
                .run();
        });
    }

    async scaleVideo(inputFile, params, outputDir, progressCallback = null, workflowId = null) {
        console.log('收到的缩放参数:', JSON.stringify(params, null, 2));
        
        let width, height, maintainAspectRatio = false;
        
        // 处理不同的参数格式
        if (params.scaleMode === 'dimensions') {
            // 指定尺寸模式
            width = params.width;
            height = params.height;
            maintainAspectRatio = params.keepAspectRatio || false;
            
            // 参数验证
            if (!width && !height) {
                throw new Error('缩放模式为指定尺寸时，至少需要提供宽度或高度');
            }
            if (width && width <= 0) {
                throw new Error(`无效的宽度参数: ${width}`);
            }
            if (height && height <= 0) {
                throw new Error(`无效的高度参数: ${height}`);
            }
        } else if (params.scaleMode === 'ratio') {
            // 缩放比例模式
            const scaleRatio = params.scaleRatio;
            if (!scaleRatio || scaleRatio <= 0) {
                throw new Error(`无效的缩放比例: ${scaleRatio}`);
            }
            
            // 获取原视频尺寸来计算目标尺寸
            const resolvedPath = await this.findFileByName(inputFile);
            if (!resolvedPath) {
                throw new Error(`找不到输入文件: ${inputFile}`);
            }
            
            const videoInfo = await this.getVideoInfoInternal(resolvedPath);
            width = Math.round(videoInfo.width * scaleRatio);
            height = Math.round(videoInfo.height * scaleRatio);
            maintainAspectRatio = true; // 比例缩放总是保持宽高比
        } else {
            // 兼容旧格式
            width = params.width;
            height = params.height;
            maintainAspectRatio = params.maintainAspectRatio || params.keepAspectRatio || false;
            
            // 参数验证
            if (!width || !height || width <= 0 || height <= 0) {
                throw new Error(`无效的缩放参数: width=${width}, height=${height}`);
            }
        }
        
        const resolvedPath = await this.findFileByName(inputFile);
        if (!resolvedPath) {
            throw new Error(`找不到输入文件: ${inputFile}`);
        }
        
        // 检查输入文件是否存在
        if (!await fs.pathExists(resolvedPath)) {
            throw new Error(`输入文件不存在: ${resolvedPath}`);
        }
        
        // 确保输出目录存在
        await fs.ensureDir(outputDir);
        
        const outputFile = path.join(outputDir, `scaled_${Date.now()}_${path.basename(resolvedPath)}`);
        console.log(`开始缩放视频: ${resolvedPath} -> ${outputFile}`);
        console.log(`缩放参数: ${width}x${height}, 保持宽高比: ${maintainAspectRatio}`);
        
        // 发送开始信息到前端界面
        if (progressCallback && workflowId) {
            progressCallback({
                workflowId,
                type: 'info',
                message: `开始缩放视频: ${path.basename(resolvedPath)}`,
                percent: 0
            });
        }

        let scaleFilter;
        if (maintainAspectRatio) {
            if (width && height) {
                scaleFilter = `scale=${width}:${height}:force_original_aspect_ratio=decrease`;
            } else if (width) {
                scaleFilter = `scale=${width}:-1`; // 保持宽高比，自动计算高度
            } else if (height) {
                scaleFilter = `scale=-1:${height}`; // 保持宽高比，自动计算宽度
            }
        } else {
            if (width && height) {
                scaleFilter = `scale=${width}:${height}`;
            } else {
                throw new Error('非保持宽高比模式下必须同时提供宽度和高度');
            }
        }
        
        console.log(`使用缩放滤镜: ${scaleFilter}`);

        return new Promise((resolve, reject) => {
            const command = ffmpeg(resolvedPath)
                .videoFilters(scaleFilter)
                .outputOptions([
                    '-c:v', 'libx264',  // 使用H.264编码器
                    '-preset', 'medium', // 编码预设
                    '-crf', '23',       // 质量控制
                    '-c:a', 'copy'      // 复制音频流
                ])
                .output(outputFile);
                
            command.on('start', (cmdLine) => {
                console.log('FFmpeg命令行:', cmdLine);
            });
            
            command.on('progress', (progress) => {
                const progressText = `缩放进度: ${progress.percent ? progress.percent.toFixed(1) + '%' : '处理中...'}`;
                console.log(progressText);
                
                // 发送进度信息到前端界面
                if (progressCallback && workflowId) {
                    progressCallback({
                        workflowId,
                        type: 'progress',
                        message: progressText,
                        percent: progress.percent || 0
                    });
                }
            });
            
            command.on('end', () => {
                console.log('视频缩放完成:', outputFile);
                
                // 发送完成信息到前端界面
                if (progressCallback && workflowId) {
                    progressCallback({
                        workflowId,
                        type: 'success',
                        message: `视频缩放完成: ${path.basename(outputFile)}`,
                        percent: 100
                    });
                }
                
                resolve({
                    type: 'scale',
                    inputFiles: [resolvedPath],
                    outputFiles: [outputFile],
                    params
                });
            });
            
            command.on('error', (error) => {
                console.error('FFmpeg缩放错误:', error.message);
                console.error('错误详情:', error);
                
                // 提供更详细的错误信息
                let errorMessage = `视频缩放失败: ${error.message}`;
                if (error.message.includes('Invalid data found')) {
                    errorMessage += '\n可能原因: 输入文件损坏或格式不支持';
                } else if (error.message.includes('No such file')) {
                    errorMessage += '\n可能原因: 文件路径包含特殊字符或文件不存在';
                } else if (error.message.includes('Permission denied')) {
                    errorMessage += '\n可能原因: 没有写入权限或文件被占用';
                } else if (error.message.includes('scale')) {
                    errorMessage += '\n可能原因: 缩放参数无效或不支持的分辨率';
                }
                
                // 发送错误信息到前端界面
                if (progressCallback && workflowId) {
                    progressCallback({
                        workflowId,
                        type: 'error',
                        message: errorMessage,
                        percent: 0
                    });
                }
                
                reject(new Error(errorMessage));
            });
            
            command.run();
        });
    }

    async addWatermark(inputFile, params, outputDir) {
        const { watermarkType, watermarkFile, text, fontSize = 24, color = '#ffffff', position = 'top-right', opacity = 0.5, margin = 20 } = params;
        const resolvedVideoPath = await this.findFileByName(inputFile);
        
        if (!resolvedVideoPath) {
            throw new Error(`找不到输入文件: ${inputFile}`);
        }

        const outputFile = path.join(outputDir, `watermarked_${Date.now()}_${path.basename(resolvedVideoPath)}`);

        if (watermarkType === 'text') {
            // 文字水印处理
            if (!text) {
                throw new Error('文字水印需要提供文字内容');
            }

            // 转换颜色格式
            const hexColor = this.colorToHex(color);
            
            // 构建文字水印滤镜
            let textFilter;
            switch (position) {
                case 'top-left':
                    textFilter = `drawtext=text='${text}':fontsize=${fontSize}:fontcolor=0x${hexColor}:x=${margin}:y=${margin}`;
                    break;
                case 'top-right':
                    textFilter = `drawtext=text='${text}':fontsize=${fontSize}:fontcolor=0x${hexColor}:x=w-tw-${margin}:y=${margin}`;
                    break;
                case 'bottom-left':
                    textFilter = `drawtext=text='${text}':fontsize=${fontSize}:fontcolor=0x${hexColor}:x=${margin}:y=h-th-${margin}`;
                    break;
                case 'bottom-right':
                    textFilter = `drawtext=text='${text}':fontsize=${fontSize}:fontcolor=0x${hexColor}:x=w-tw-${margin}:y=h-th-${margin}`;
                    break;
                case 'center':
                    textFilter = `drawtext=text='${text}':fontsize=${fontSize}:fontcolor=0x${hexColor}:x=(w-tw)/2:y=(h-th)/2`;
                    break;
                default:
                    textFilter = `drawtext=text='${text}':fontsize=${fontSize}:fontcolor=0x${hexColor}:x=w-tw-${margin}:y=${margin}`;
            }

            return new Promise((resolve, reject) => {
                ffmpeg(resolvedVideoPath)
                    .videoFilters(textFilter)
                    .output(outputFile)
                    .on('end', () => {
                        resolve({
                            type: 'watermark',
                            inputFiles: [resolvedVideoPath],
                            outputFiles: [outputFile],
                            params
                        });
                    })
                    .on('error', reject)
                    .run();
            });
        } else {
            // 图片水印处理
            const resolvedWatermarkPath = await this.findFileByName(watermarkFile);
            
            if (!resolvedWatermarkPath) {
                throw new Error(`找不到水印文件: ${watermarkFile}`);
            }

            let overlayFilter;
            switch (position) {
                case 'top-left':
                    overlayFilter = `overlay=${margin}:${margin}:format=auto,format=yuv420p`;
                    break;
                case 'top-right':
                    overlayFilter = `overlay=main_w-overlay_w-${margin}:${margin}:format=auto,format=yuv420p`;
                    break;
                case 'bottom-left':
                    overlayFilter = `overlay=${margin}:main_h-overlay_h-${margin}:format=auto,format=yuv420p`;
                    break;
                case 'bottom-right':
                    overlayFilter = `overlay=main_w-overlay_w-${margin}:main_h-overlay_h-${margin}:format=auto,format=yuv420p`;
                    break;
                case 'center':
                    overlayFilter = `overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2:format=auto,format=yuv420p`;
                    break;
                default:
                    overlayFilter = `overlay=main_w-overlay_w-${margin}:${margin}:format=auto,format=yuv420p`;
            }

            return new Promise((resolve, reject) => {
                ffmpeg(resolvedVideoPath)
                    .input(resolvedWatermarkPath)
                    .complexFilter([overlayFilter])
                    .output(outputFile)
                    .on('end', () => {
                        resolve({
                            type: 'watermark',
                            inputFiles: [resolvedVideoPath, resolvedWatermarkPath],
                            outputFiles: [outputFile],
                            params
                        });
                    })
                    .on('error', reject)
                    .run();
            });
        }
    }

    async mergeVideos(inputFiles, params, outputDir, progressCallback = null, workflowId = null) {
        const outputFile = path.join(outputDir, `merged_${Date.now()}.mp4`);
        const { mergeType = 'concat', filesToMerge } = params;
        
        // 发送日志的辅助函数
        const sendLog = (message) => {
            console.log(message);
            if (progressCallback && workflowId) {
                progressCallback({
                    workflowId,
                    status: 'processing',
                    message
                });
            }
        };

        // 确定要合并的文件列表：优先使用params.filesToMerge，否则使用inputFiles
        const filesToProcess = filesToMerge && filesToMerge.length > 0 ? filesToMerge : inputFiles;
        
        console.log('合并操作 - 输入参数:');
        console.log('  inputFiles:', inputFiles);
        console.log('  params.filesToMerge:', filesToMerge);
        console.log('  实际处理的文件列表:', filesToProcess);

        // 首先检查FFmpeg是否可用
        const ffmpegAvailable = await this.checkFFmpeg();
        if (!ffmpegAvailable) {
            throw new Error('FFmpeg未安装或不可用。请安装FFmpeg后重试。\n请参考 FFMPEG_INSTALL_GUIDE.md 文档进行安装。');
        }

        return new Promise(async (resolve, reject) => {
            try {
                if (mergeType === 'concat') {
                    const fs = require('fs-extra');
                    const tempDir = path.join(outputDir, `temp_${Date.now()}`);
                    const tempListFile = path.join(tempDir, 'file_list.txt');
                    
                    try {
                        // 确保输出目录和临时目录存在
                        await fs.ensureDir(outputDir);
                        await fs.ensureDir(tempDir);
                        
                        // 验证所有输入文件是否存在
                        sendLog('验证输入文件...');
                        const resolvedPaths = [];
                        for (const file of filesToProcess) {
                            // 先尝试直接路径
                            if (await fs.pathExists(file)) {
                                resolvedPaths.push(file);
                                sendLog(`✓ 文件存在: ${file}`);
                            } else {
                                // 如果直接路径不存在，尝试通过文件名查找
                                const resolvedPath = await this.findFileByName(file);
                                if (resolvedPath) {
                                    resolvedPaths.push(resolvedPath);
                                    sendLog(`✓ 通过文件名找到: ${file} -> ${resolvedPath}`);
                                } else {
                                    throw new Error(`文件不存在: ${file}`);
                                }
                            }
                        }
                        
                        // 创建临时文件来处理复杂路径
                        sendLog('创建临时文件...');
                        const tempFiles = await this.createTempSymlinksFromPaths(resolvedPaths, tempDir);
                        
                        // 创建文件列表，使用正确的路径格式
                        const fileList = tempFiles.map(file => {
                            // 将路径转换为正斜杠格式，并确保路径正确
                            const normalizedPath = file.replace(/\\/g, '/');
                            // 不使用引号，因为FFmpeg在Windows上处理引号有问题
                            return `file ${normalizedPath}`;
                        }).join('\n');
                        
                        console.log('创建文件列表:', fileList);
                        await fs.writeFile(tempListFile, fileList, 'utf8');
                        
                        // 验证临时文件是否创建成功
                        if (!await fs.pathExists(tempListFile)) {
                            throw new Error('临时文件创建失败');
                        }
                        
                        sendLog('开始FFmpeg合并...');
                        
                        // 使用concat demuxer
                        const command = ffmpeg();
                        command
                            .input(tempListFile)
                            .inputOptions(['-f', 'concat', '-safe', '0'])
                            .outputOptions([
                                // 尝试使用copy方式，但添加一些参数确保音频正确处理
                                '-c:v', 'copy',  // 复制视频流
                                '-c:a', 'aac',   // 重新编码音频为AAC
                                '-b:a', '192k',  // 设置音频比特率
                                '-ar', '44100',  // 设置音频采样率
                                '-ac', '2',      // 设置音频通道数为2（立体声）
                                '-avoid_negative_ts', 'make_zero',  // 避免负时间戳问题
                                '-vsync', '2'    // 帮助处理可变帧率问题
                            ])
                            .output(outputFile)
                            .on('start', (commandLine) => {
                                sendLog('FFmpeg命令: ' + commandLine);
                            })
                            .on('progress', (progress) => {
                                // 确保进度值在0-100%之间
                                const rawPercent = progress.percent || 0;
                                const percent = Math.min(Math.max(Math.round(rawPercent), 0), 100);
                                
                                // 发送进度更新
                                if (progressCallback && workflowId) {
                                    progressCallback({
                                        workflowId,
                                        status: 'processing',
                                        progress: percent,
                                        message: `合并进度: ${percent}%`
                                    });
                                }
                                
                                // 只在特定进度点显示进度，减少日志量
                                if (percent % 5 === 0 || percent === 100) {
                                    sendLog('合并进度: ' + percent + '%');
                                }
                            })
                            .on('end', async () => {
                                sendLog('视频合并完成: ' + outputFile);
                                
                                // 发送完成状态
                                if (progressCallback && workflowId) {
                                    progressCallback({
                                        workflowId,
                                        status: 'completed',
                                        progress: 100,
                                        message: '视频合并完成'
                                    });
                                }
                                
                                // 清理临时文件和目录
                                try {
                                    await fs.remove(tempDir);
                                    sendLog('临时目录清理完成');
                                } catch (e) {
                                    console.warn('清理临时目录失败:', e.message);
                                }
                                resolve({
                                    type: 'merge',
                                    inputFiles: filesToProcess,
                                    outputFiles: [outputFile],
                                    params
                                });
                            })
                            .on('error', async (err, stdout, stderr) => {
                                sendLog('使用 concat demuxer 合并视频失败: ' + err.message);
                                console.error('FFmpeg stdout:', stdout);
                                console.error('FFmpeg stderr:', stderr);
                                
                                // 清理临时文件和目录
                                try {
                                    await fs.remove(tempDir);
                                } catch (e) {
                                    console.warn('清理临时目录失败:', e.message);
                                }
                                
                                // 如果concat demuxer失败，尝试重新编码方法
                                sendLog('Concat demuxer 失败，尝试使用重新编码方法...');
                                try {
                                    const result = await this.mergeVideosWithReencoding(inputFiles, outputFile, params, progressCallback, workflowId, sendLog);
                                    resolve(result);
                                } catch (reencodeError) {
                                    const errorMessage = `视频合并失败。\n原始错误: ${err.message}\nFFmpeg stderr: ${stderr}\n重新编码也失败: ${reencodeError.message}`;
                                    sendLog(errorMessage);
                                    reject(new Error(errorMessage));
                                }
                            })
                            .run();
                            
                    } catch (error) {
                        sendLog('创建临时文件失败: ' + error.message);
                        console.error('创建临时文件失败:', error);
                        // 清理临时目录
                        try {
                            await fs.remove(tempDir);
                        } catch (e) {
                            console.warn('清理临时目录失败:', e.message);
                        }
                        // 如果创建临时文件失败，使用重新编码方法
                        try {
                            sendLog('尝试使用重新编码方法...');
                            const result = await this.mergeVideosWithReencoding(inputFiles, outputFile, params, progressCallback, workflowId, sendLog);
                            resolve(result);
                        } catch (reencodeError) {
                            const errorMessage = `创建临时文件失败: ${error.message}\n重新编码也失败: ${reencodeError.message}`;
                            sendLog(errorMessage);
                            reject(new Error(errorMessage));
                        }
                    }
                } else {
                    reject(new Error(`不支持的合并类型: ${mergeType}`));
                }
            } catch (error) {
                console.error('合并视频异常:', error);
                reject(error);
            }
        });
    }

    async addBackgroundImage(inputFile, params, outputDir, progressCallback = null, workflowId = null) {
        const { backgroundImages, scaleMode = 'fill' } = params;
        
        if (!backgroundImages || backgroundImages.length === 0) {
            throw new Error('背景图片列表不能为空');
        }

        // 发送日志的辅助函数
        const sendLog = (message) => {
            console.log(message);
            if (progressCallback && workflowId) {
                progressCallback({
                    workflowId,
                    status: 'processing',
                    message
                });
            }
        };

        try {
            sendLog('开始添加背景图片处理...');
            sendLog(`输入音频文件: ${path.basename(inputFile)}`);
            sendLog(`背景图片数量: ${backgroundImages.length}`);
            sendLog(`缩放模式: ${scaleMode}`);

            // 解析输入音频文件路径
            sendLog('正在解析输入音频文件路径...');
            const resolvedAudioPath = await this.findFileByName(inputFile);
            if (!resolvedAudioPath) {
                throw new Error(`找不到指定的音频文件: ${inputFile}`);
            }
            sendLog(`已找到音频文件路径: ${resolvedAudioPath}`);

            // 获取音频信息
            sendLog('正在获取音频信息...');
            const audioInfo = await this.getAudioInfo(resolvedAudioPath);
            const audioDuration = audioInfo.duration;
            sendLog(`音频时长: ${audioDuration}秒`);

            // 生成输出文件名
            const outputFile = path.join(outputDir, `background_image_${Date.now()}.mp4`);

            // 随机选择背景图片并解析路径
            const selectedImagePath = backgroundImages[Math.floor(Math.random() * backgroundImages.length)];
            sendLog(`已选择背景图片: ${path.basename(selectedImagePath)}`);

            // 解析背景图片路径
            let selectedImage;
            if (path.isAbsolute(selectedImagePath) && fs.existsSync(selectedImagePath)) {
                // 如果是绝对路径且文件存在，直接使用
                selectedImage = selectedImagePath;
                sendLog(`已找到绝对路径: ${selectedImage}`);
            } else {
                // 否则通过文件名查找
                selectedImage = await this.findFileByName(selectedImagePath);
                if (!selectedImage) {
                    throw new Error(`找不到指定的背景图片文件: ${selectedImagePath}`);
                }
                sendLog(`已找到背景图片: ${selectedImage}`);
            }

            // 构建FFmpeg命令
            sendLog('正在构建FFmpeg命令...');
            
            // 为了解决Windows下FFmpeg无法处理Unicode路径的问题，创建临时文件
            const tempAudioPath = path.join(outputDir, `temp_audio_${Date.now()}.mp3`);
            
            try {
                // 先复制音频文件到临时路径，避免Unicode路径问题
                await fs.copy(resolvedAudioPath, tempAudioPath);
                sendLog(`创建临时音频文件: ${tempAudioPath}`);
            } catch (copyError) {
                sendLog(`复制临时音频文件失败: ${copyError.message}`);
                throw copyError;
            }
            
            return new Promise((resolve, reject) => {
                const command = ffmpeg()
                    .input(selectedImage)
                    .inputOptions(['-loop', '1', '-t', audioDuration.toString()])
                    .input(tempAudioPath)
                    .outputOptions([
                        '-c:v libx264',
                        '-c:a aac',
                        '-pix_fmt yuv420p',
                        '-r 30',
                        '-map 0:v:0',
                        '-map 1:a:0'
                    ]);

                // 根据缩放模式添加视频滤镜
                let videoFilter;
                switch (scaleMode) {
                    case 'fill':
                        // 填充模式，裁剪保持宽高比
                        videoFilter = 'scale=1920:1080:force_original_aspect_ratio=increase,crop=1920:1080';
                        break;
                    case 'fit':
                        // 适应模式，完整显示图片，可能有黑边
                        videoFilter = 'scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2:black';
                        break;
                    case 'stretch':
                        // 拉伸模式，可能变形
                        videoFilter = 'scale=1920:1080';
                        break;
                    default:
                        videoFilter = 'scale=1920:1080:force_original_aspect_ratio=increase,crop=1920:1080';
                }

                command
                    .videoFilters(videoFilter)
                    .output(outputFile);

                let lastReportedProgress = 0;
                
                command
                    .on('start', (commandLine) => {
                        sendLog('FFmpeg命令已启动');
                        sendLog(`命令行: ${commandLine}`);
                        
                        // 发送开始处理的进度
                        if (progressCallback && workflowId) {
                            progressCallback({
                                workflowId,
                                status: 'processing',
                                progress: 0,
                                message: '开始处理背景图片...'
                            });
                        }
                    })
                    .on('progress', (progress) => {
                        if (!progressCallback || !workflowId) return;
                        
                        let percent = 0;
                        
                        // 优先使用基于时间的进度计算
                        if (progress.timemark && audioDuration) {
                            const currentTime = this.timeToSeconds(progress.timemark);
                            percent = Math.min(Math.round((currentTime / audioDuration) * 100), 99); // 最大99%，避免提前显示100%
                        } 
                        // 备用：使用FFmpeg提供的百分比，但限制最大值
                        else if (progress.percent) {
                            percent = Math.min(Math.round(progress.percent), 99);
                        }
                        
                        // 确保进度值合理且递增
                        percent = Math.max(percent, lastReportedProgress);
                        percent = Math.min(Math.max(percent, 0), 99);
                        
                        // 只在进度有实际变化时更新（至少1%的变化）
                        if (percent > lastReportedProgress) {
                            lastReportedProgress = percent;
                            progressCallback({
                                workflowId,
                                status: 'processing',
                                progress: percent,
                                message: `处理进度: ${percent}% (${progress.timemark || '计算中...'})`
                            });
                        }
                    })
                    .on('end', async () => {
                        sendLog('背景图片添加完成');
                        
                        // 只有在处理真正完成时才发送100%进度
                        if (progressCallback && workflowId) {
                            progressCallback({
                                workflowId,
                                status: 'completed',
                                progress: 100,
                                message: '背景图片处理完成'
                            });
                        }
                        
                        // 清理临时音频文件
                        try {
                            await fs.remove(tempAudioPath);
                            sendLog('临时音频文件清理完成');
                        } catch (cleanupError) {
                            console.warn('清理临时音频文件失败:', cleanupError.message);
                        }
                        
                        resolve({
                            type: 'background',
                            inputFiles: [inputFile],
                            outputFiles: [outputFile],
                            params
                        });
                    })
                    .on('error', async (err) => {
                        sendLog(`处理失败: ${err.message}`);
                        
                        // 清理临时音频文件
                        try {
                            await fs.remove(tempAudioPath);
                            sendLog('临时音频文件清理完成');
                        } catch (cleanupError) {
                            console.warn('清理临时音频文件失败:', cleanupError.message);
                        }
                        
                        reject(err);
                    })
                    .run();
            });

        } catch (error) {
            sendLog(`处理失败: ${error.message}`);
            throw error;
        }
    }

    // 辅助方法
    calculateDuration(startTime, endTime) {
        const start = this.timeToSeconds(startTime);
        // 如果endTime为null，返回null让FFmpeg处理到视频结束
        if (endTime === null || endTime === undefined) {
            return null;
        }
        const end = this.timeToSeconds(endTime);
        return end - start;
    }

    timeToSeconds(time) {
        // 处理null或undefined的情况
        if (time === null || time === undefined) {
            return null;
        }
        // 确保time是字符串
        if (typeof time !== 'string') {
            return null;
        }
        const parts = time.split(':').map(Number);
        return parts[0] * 3600 + parts[1] * 60 + parts[2];
    }
    
    // 将秒数格式化为时间字符串 (HH:MM:SS)
    formatTime(seconds) {
        const hours = Math.floor(seconds / 3600);
        const mins = Math.floor((seconds % 3600) / 60);
        const secs = Math.floor(seconds % 60);
        return `${hours.toString().padStart(2, '0')}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
    }

    getWorkflowStatus(workflowId) {
        return this.processingStatus.get(workflowId) || { status: 'not_found' };
    }

    getWorkflowDetails(workflowId) {
        return this.workflowQueue.get(workflowId);
    }

    async cleanupWorkflow(workflowId) {
        const workflow = this.workflowQueue.get(workflowId);
        if (workflow && workflow.results) {
            for (const result of workflow.results) {
                if (result.outputFiles && workflow.finalOutputs) {
                    for (const file of result.outputFiles) {
                        if (!workflow.finalOutputs.includes(file)) {
                            try {
                                await fs.remove(file);
                            } catch (error) {
                                console.warn(`清理文件失败: ${file}`, error.message);
                            }
                        }
                    }
                }
            }
        }
    }

    convertTxtToSrt(text, videoDuration, mode, frequency, skipEmptyLines) {
        let lines = text.split('\n');
        if (skipEmptyLines) {
            lines = lines.filter(line => line.trim() !== '');
        }
        let srt = '';
        let startTime = 0;
        const maxLineLength = 60;
        const lineCount = lines.length;
        let durationPerLine;
    
        if (mode === 'proportional') {
            durationPerLine = videoDuration / lineCount;
        } else {
            durationPerLine = frequency;
        }
    
        let index = 1;
        lines.forEach((line) => {
            let currentLine = line.trim();
            if (currentLine.length === 0 && !skipEmptyLines) {
                const start = this.formatSrtTime(startTime);
                const end = this.formatSrtTime(startTime + durationPerLine);
                srt += `${index}\n${start} --> ${end}\n\n`;
                startTime += durationPerLine;
                index++;
                return;
            }
            while (currentLine.length > 0) {
                let displayLine = currentLine.slice(0, maxLineLength);
                currentLine = currentLine.slice(maxLineLength);
                const start = this.formatSrtTime(startTime);
                const end = this.formatSrtTime(startTime + durationPerLine);
                srt += `${index}\n${start} --> ${end}\n${displayLine}\n\n`;
                startTime += durationPerLine;
                index++;
            }
        });
        return srt;
    }

    formatSrtTime(seconds) {
        const hours = Math.floor(seconds / 3600);
        const mins = Math.floor((seconds % 3600) / 60);
        const secs = Math.floor(seconds % 60);
        const ms = Math.floor((seconds % 1) * 1000);
        return `${hours.toString().padStart(2, '0')}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')},${ms.toString().padStart(3, '0')}`;
    }

    /**
     * 获取音频信息
     * @param {string} inputFile - 输入音频文件
     * @returns {Promise<Object>} 音频信息 {duration}
     */
    async getVideoInfoInternal(inputFile) {
        return new Promise((resolve, reject) => {
            ffmpeg.ffprobe(inputFile, (err, metadata) => {
                if (err) {
                    reject(err);
                    return;
                }

                const videoStream = metadata.streams.find(stream => stream.codec_type === 'video');
                if (!videoStream) {
                    reject(new Error('未找到视频流'));
                    return;
                }

                resolve({
                    width: videoStream.width,
                    height: videoStream.height,
                    duration: parseFloat(metadata.format.duration) || 0
                });
            });
        });
    }

    async getAudioInfo(inputFile) {
        const resolvedPath = await this.findFileByName(inputFile);
        if (!resolvedPath) {
            throw new Error(`找不到音频文件: ${inputFile}`);
        }

        return new Promise((resolve, reject) => {
            ffmpeg.ffprobe(resolvedPath, (err, metadata) => {
                if (err) {
                    console.error('获取音频信息失败:', err);
                    reject(err);
                    return;
                }

                const info = {
                    duration: metadata.format.duration
                };

                resolve(info);
            });
        });
    }

    /**
     * 使用重新编码的方式合并视频（备用方法）
     */
    async mergeVideosWithReencoding(inputFiles, outputFile, params, progressCallback, workflowId, sendLog) {
        const tempDir = path.join(os.tmpdir(), `video_merge_${Date.now()}`);
        let tempFiles = [];
        
        try {
            await fs.ensureDir(tempDir);
            sendLog('创建临时目录用于重新编码合并');
            
            // 创建临时文件副本以避免路径问题
            tempFiles = await this.createTempSymlinks(inputFiles, tempDir);
            sendLog(`创建了 ${tempFiles.length} 个临时文件`);
            
            // 构建复杂的滤镜链
            const filterChain = this.buildMergeFilterChain(tempFiles, params.mergeType);
            
            return new Promise((resolve, reject) => {
                const command = ffmpeg();
                
                // 添加所有输入文件
                tempFiles.forEach(file => {
                    command.input(file);
                });
                
                // 应用滤镜链
                command.complexFilter(filterChain, ['v', 'a']);
                
                // 输出设置
                command
                    .outputOptions([
                        '-map', '[v]',
                        '-map', '[a]',
                        '-c:v', 'libx264',
                        '-preset', 'medium',
                        '-crf', '23',
                        '-c:a', 'aac',
                        '-b:a', '128k',
                        '-movflags', '+faststart'
                    ])
                    .output(outputFile)
                    .on('start', (commandLine) => {
                        sendLog('开始重新编码合并视频');
                        sendLog(`FFmpeg命令: ${commandLine}`);
                    })
                    .on('progress', (progress) => {
                        if (progressCallback && workflowId) {
                            const percent = Math.min(Math.round(progress.percent || 0), 99);
                            progressCallback({
                                workflowId,
                                status: 'processing',
                                progress: percent,
                                message: `重新编码合并进度: ${percent}%`
                            });
                        }
                    })
                    .on('end', async () => {
                        sendLog('重新编码合并完成');
                        
                        if (progressCallback && workflowId) {
                            progressCallback({
                                workflowId,
                                status: 'completed',
                                progress: 100,
                                message: '视频合并完成'
                            });
                        }
                        
                        // 清理临时文件
                        await this.cleanupTempFiles(tempDir);
                        
                        resolve({
                            type: 'merge',
                            inputFiles,
                            outputFiles: [outputFile],
                            params
                        });
                    })
                    .on('error', async (err) => {
                        sendLog(`重新编码合并失败: ${err.message}`);
                        
                        // 清理临时文件
                        await this.cleanupTempFiles(tempDir);
                        
                        reject(err);
                    })
                    .run();
            });
            
        } catch (error) {
            // 清理临时文件
            await this.cleanupTempFiles(tempDir);
            throw error;
        }
    }

    /**
     * 构建合并滤镜链
     */
    buildMergeFilterChain(inputFiles, mergeType) {
        const videoInputs = inputFiles.map((_, i) => `[${i}:v]`);
        const audioInputs = inputFiles.map((_, i) => `[${i}:a]`);
        
        let filterChain = [];
        
        // 标准化视频流（缩放、填充、帧率）
        inputFiles.forEach((_, i) => {
            filterChain.push({
                filter: 'scale',
                options: '1920:1080:force_original_aspect_ratio=decrease',
                inputs: `[${i}:v]`,
                outputs: `[v${i}_scaled]`
            });
            
            filterChain.push({
                filter: 'pad',
                options: '1920:1080:(ow-iw)/2:(oh-ih)/2:black',
                inputs: `[v${i}_scaled]`,
                outputs: `[v${i}_padded]`
            });
            
            filterChain.push({
                filter: 'fps',
                options: '30',
                inputs: `[v${i}_padded]`,
                outputs: `[v${i}_final]`
            });
        });
        
        // 标准化音频流
        inputFiles.forEach((_, i) => {
            filterChain.push({
                filter: 'aresample',
                options: '44100',
                inputs: `[${i}:a]`,
                outputs: `[a${i}_resampled]`
            });
            
            filterChain.push({
                filter: 'aformat',
                options: 'sample_fmts=fltp:channel_layouts=stereo',
                inputs: `[a${i}_resampled]`,
                outputs: `[a${i}_final]`
            });
        });
        
        // 合并视频流
        const finalVideoInputs = inputFiles.map((_, i) => `[v${i}_final]`);
        if (mergeType === 'hstack') {
            filterChain.push({
                filter: 'hstack',
                options: `inputs=${inputFiles.length}`,
                inputs: finalVideoInputs,
                outputs: '[v]'
            });
        } else if (mergeType === 'vstack') {
            filterChain.push({
                filter: 'vstack',
                options: `inputs=${inputFiles.length}`,
                inputs: finalVideoInputs,
                outputs: '[v]'
            });
        } else {
            // concat 模式
            const concatInputs = [];
            inputFiles.forEach((_, i) => {
                concatInputs.push(`[v${i}_final]`, `[a${i}_final]`);
            });
            
            filterChain.push({
                filter: 'concat',
                options: `n=${inputFiles.length}:v=1:a=1`,
                inputs: concatInputs,
                outputs: ['[v]', '[a]']
            });
            
            return filterChain;
        }
        
        // 合并音频流（非concat模式）
        const finalAudioInputs = inputFiles.map((_, i) => `[a${i}_final]`);
        filterChain.push({
            filter: 'amix',
            options: `inputs=${inputFiles.length}:duration=longest`,
            inputs: finalAudioInputs,
            outputs: '[a]'
        });
        
        return filterChain;
    }

    /**
     * 创建临时符号链接或副本（从已解析的文件路径）
     */
    async createTempSymlinksFromPaths(resolvedPaths, tempDir) {
        const tempFiles = [];
        
        for (let i = 0; i < resolvedPaths.length; i++) {
            const resolvedPath = resolvedPaths[i];
            
            const ext = path.extname(resolvedPath);
            const tempFileName = `input_${i}${ext}`;
            const tempFilePath = path.join(tempDir, tempFileName);
            
            try {
                // 在Windows上复制文件，其他系统尝试符号链接
                if (process.platform === 'win32') {
                    await fs.copy(resolvedPath, tempFilePath);
                } else {
                    try {
                        await fs.symlink(resolvedPath, tempFilePath);
                    } catch (symlinkError) {
                        // 如果符号链接失败，回退到复制
                        await fs.copy(resolvedPath, tempFilePath);
                    }
                }
                tempFiles.push(tempFilePath);
            } catch (error) {
                throw new Error(`创建临时文件失败: ${error.message}`);
            }
        }
        
        return tempFiles;
    }

    /**
     * 创建临时符号链接或副本
     */
    async createTempSymlinks(inputFiles, tempDir) {
        const tempFiles = [];
        
        for (let i = 0; i < inputFiles.length; i++) {
            const inputFile = inputFiles[i];
            const resolvedPath = await this.findFileByName(inputFile);
            if (!resolvedPath) {
                throw new Error(`找不到输入文件: ${inputFile}`);
            }
            
            const ext = path.extname(resolvedPath);
            const tempFileName = `input_${i}${ext}`;
            const tempFilePath = path.join(tempDir, tempFileName);
            
            try {
                // 在Windows上复制文件，其他系统尝试符号链接
                if (process.platform === 'win32') {
                    await fs.copy(resolvedPath, tempFilePath);
                } else {
                    try {
                        await fs.symlink(resolvedPath, tempFilePath);
                    } catch (symlinkError) {
                        // 如果符号链接失败，回退到复制
                        await fs.copy(resolvedPath, tempFilePath);
                    }
                }
                tempFiles.push(tempFilePath);
            } catch (error) {
                throw new Error(`创建临时文件失败: ${error.message}`);
            }
        }
        
        return tempFiles;
    }

    /**
     * 清理临时文件
     */
    async cleanupTempFiles(tempDir) {
        try {
            await fs.remove(tempDir);
        } catch (error) {
            console.warn('清理临时文件失败:', error.message);
        }
    }

    /**
     * 安全化文件路径
     */
    sanitizeFilePath(filePath) {
        // 移除或替换可能导致问题的字符
        return filePath
            .replace(/[<>:"|?*]/g, '_')  // Windows不允许的字符
            .replace(/\s+/g, '_')        // 空格替换为下划线
            .replace(/[^\x20-\x7E]/g, '_'); // 非ASCII字符替换为下划线
    }

    /**
     * 镜像翻转视频
     */
    async mirrorVideo(inputFile, params, outputDir) {
        const { direction = 'horizontal' } = params;
        const resolvedPath = await this.findFileByName(inputFile);
        if (!resolvedPath) {
            throw new Error(`找不到输入文件: ${inputFile}`);
        }
        
        const outputFile = path.join(outputDir, `mirrored_${Date.now()}_${path.basename(resolvedPath)}`);
        
        // 构建镜像滤镜
        let filter;
        if (direction === 'horizontal') {
            filter = 'hflip';
        } else if (direction === 'vertical') {
            filter = 'vflip';
        } else {
            throw new Error(`不支持的镜像方向: ${direction}`);
        }
        
        return new Promise((resolve, reject) => {
            ffmpeg(resolvedPath)
                .videoFilters(filter)
                .output(outputFile)
                .on('end', () => {
                    resolve({
                        type: 'mirror',
                        inputFiles: [resolvedPath],
                        outputFiles: [outputFile],
                        params
                    });
                })
                .on('error', reject)
                .run();
        });
    }

    /**
     * 旋转视频
     */
    async rotateVideo(inputFile, params, outputDir) {
        const { angle = 90 } = params;
        const resolvedPath = await this.findFileByName(inputFile);
        if (!resolvedPath) {
            throw new Error(`找不到输入文件: ${inputFile}`);
        }
        
        const outputFile = path.join(outputDir, `rotated_${Date.now()}_${path.basename(resolvedPath)}`);
        
        // 构建旋转滤镜
        let filter;
        switch (angle) {
            case 90:
                filter = 'transpose=1';
                break;
            case 180:
                filter = 'transpose=1,transpose=1';
                break;
            case 270:
                filter = 'transpose=2';
                break;
            default:
                // 任意角度旋转
                filter = `rotate=${angle * Math.PI / 180}:fillcolor=black:ow=rotw(${angle * Math.PI / 180}):oh=roth(${angle * Math.PI / 180})`;
        }
        
        return new Promise((resolve, reject) => {
            ffmpeg(resolvedPath)
                .videoFilters(filter)
                .output(outputFile)
                .on('end', () => {
                    resolve({
                        type: 'rotate',
                        inputFiles: [resolvedPath],
                        outputFiles: [outputFile],
                        params
                    });
                })
                .on('error', reject)
                .run();
        });
    }

    /**
     * 调整视频播放速度
     */
    async changeSpeed(inputFile, params, outputDir) {
        const { factor = 1.0 } = params;
        const resolvedPath = await this.findFileByName(inputFile);
        if (!resolvedPath) {
            throw new Error(`找不到输入文件: ${inputFile}`);
        }
        
        const outputFile = path.join(outputDir, `speed_${Date.now()}_${path.basename(resolvedPath)}`);
        
        // 构建变速滤镜
        const videoFilter = `setpts=${1/factor}*PTS`;
        const audioFilter = `atempo=${factor}`;
        
        return new Promise((resolve, reject) => {
            ffmpeg(resolvedPath)
                .videoFilters(videoFilter)
                .audioFilters(audioFilter)
                .output(outputFile)
                .on('end', () => {
                    resolve({
                        type: 'speed',
                        inputFiles: [resolvedPath],
                        outputFiles: [outputFile],
                        params
                    });
                })
                .on('error', reject)
                .run();
        });
    }

    /**
     * 添加马赛克
     * @param {string} inputFile - 输入文件
     * @param {Object} params - 参数 {regions, timeSegments, thickness, processingMode}
     * @param {string} outputDir - 输出目录
     * @param {Function} progressCallback - 进度回调函数
     * @param {string} workflowId - 工作流ID
     */
    async addMosaic(inputFile, params, outputDir, progressCallback = null, workflowId = null) {
        const {
            regions = [{ top: 100, bottom: 100, left: 100, right: 100 }],
            timeSegments = [{ start: '00:00:00', end: null }],
            thickness = 20,
            processingMode = 'pixel-based'
        } = params;

        const resolvedPath = await this.findFileByName(inputFile);
        if (!resolvedPath) {
            throw new Error(`找不到输入文件: ${inputFile}`);
        }

        const outputFile = path.join(outputDir, `mosaic_${Date.now()}_${path.basename(resolvedPath)}`);

        // 发送开始日志给前端
        const sendLog = (message) => {
            console.log(message);
            if (progressCallback && workflowId) {
                progressCallback({
                    workflowId,
                    status: 'processing',
                    message
                });
            }
        };

        sendLog('🎭 开始马赛克处理...');
        sendLog(`📧 输入文件: ${path.basename(resolvedPath)}`);
        sendLog(`📐 马赛克区域数量: ${regions.length}`);
        sendLog(`⏰ 时间段: ${timeSegments ? timeSegments.length : 0} 个`);
        sendLog(`🔧 马赛克强度: ${thickness}`);

        return new Promise((resolve, reject) => {
            try {
                sendLog('🔨 正在构建马赛克滤镜链...');

                // 构建复杂的滤镜链来处理多个马赛克区域和时间段
                const filterChain = this.buildMosaicFilterChain(regions, timeSegments, thickness, processingMode);

                sendLog('✅ 马赛克滤镜链构建完成');
                sendLog(`🔗 滤镜链: ${filterChain}`);

                sendLog('🚀 开始FFmpeg处理...');

                const command = ffmpeg(resolvedPath);

                if (filterChain) {
                    sendLog('📊 使用复杂滤镜处理模式');
                    // 使用complexFilter处理复杂的滤镜链
                    command
                        .complexFilter([filterChain])
                        .outputOptions(['-map', '[v]', '-map', '0:a?'])
                        .output(outputFile);
                } else {
                    sendLog('📋 使用直接复制模式');
                    // 如果没有滤镜链，直接复制
                    command.output(outputFile);
                }

                command
                    .on('start', (commandLine) => {
                        sendLog(`🎬 FFmpeg命令: ${commandLine}`);
                    })
                    .on('progress', (progress) => {
                        if (progressCallback && workflowId) {
                            const percent = Math.min(Math.round(progress.percent || 0), 99);
                            progressCallback({
                                workflowId,
                                status: 'processing',
                                progress: percent,
                                message: `马赛克处理进度: ${percent}%`
                            });
                        }
                    })
                    .on('end', () => {
                        sendLog('🎉 马赛克处理完成!');
                        if (progressCallback && workflowId) {
                            progressCallback({
                                workflowId,
                                status: 'completed',
                                progress: 100,
                                message: '马赛克处理完成'
                            });
                        }
                        resolve({
                            type: 'mosaic',
                            inputFiles: [resolvedPath],
                            outputFiles: [outputFile],
                            params
                        });
                    })
                    .on('error', (err, stdout, stderr) => {
                        sendLog(`❌ FFmpeg处理失败: ${err.message}`);
                        if (stderr) {
                            sendLog('🔍 FFmpeg错误详情:');
                            sendLog(stderr);
                        }

                        reject(err);
                    })
                    .run();
            } catch (error) {
                sendLog(`💥 构建马赛克滤镜失败: ${error.message}`);
                reject(error);
            }
        });
    }

    /**
     * 构建马赛克滤镜链
     * @param {Array} regions - 马赛克区域列表 [{top, bottom, left, right}]
     * @param {Array} timeSegments - 时间段列表 [{start, end}]
     * @param {number} thickness - 马赛克厚度
     * @param {string} processingMode - 处理方式 ('pixel-based' 或 'area-based')
     */
    buildMosaicFilterChain(regions, timeSegments, thickness, processingMode = 'pixel-based') {
        // 如果没有区域，返回空字符串
        if (!regions || regions.length === 0) {
            console.log('⚠️ 没有马赛克区域，跳过处理');
            return '';
        }

        // 计算像素化的块大小，基于thickness参数
        const pixelSize = Math.max(Math.floor(thickness / 2), 5);
        console.log(`🔧 马赛克像素大小: ${pixelSize}`);
        console.log(`🎭 马赛克处理方式: ${processingMode}`);

        // 只处理第一个区域，确保稳定性
        const region = regions[0];
        console.log(`📐 处理马赛克区域:`, region);

        // 正确计算区域的坐标和尺寸
        // region.left, region.top 是左上角坐标
        // region.right, region.bottom 是右下角坐标
        const x = region.left;
        const y = region.top;
        const w = region.right - region.left;  // 宽度 = 右边界 - 左边界
        const h = region.bottom - region.top;  // 高度 = 下边界 - 上边界

        console.log(`📏 马赛克区域坐标: x=${x}, y=${y}, w=${w}, h=${h}`);

        let filterChain;

        if (processingMode === 'area-based') {
            // 基于区域处理：对整个选择区域进行完全马赛克覆盖，使用更大的像素块产生粗糙效果
            console.log('🎆 使用基于区域的马赛克处理');
            const areaPixelSize = Math.max(pixelSize * 3, 15); // 区域处理使用更大的像素块，产生更粗糙的效果
            console.log(`🔧 区域处理像素大小: ${areaPixelSize}`);
            filterChain = `[0:v]split[main][mosaic];[mosaic]crop=${w}:${h}:${x}:${y},scale=${Math.max(w/areaPixelSize, 1)}:${Math.max(h/areaPixelSize, 1)}:flags=neighbor,scale=${w}:${h}:flags=neighbor[mosaiced];[main][mosaiced]overlay=${x}:${y}[v]`;
        } else {
            // 基于像素处理：使用更精细的马赛克效果，保留更多细节
            console.log('🎆 使用基于像素的马赛克处理');
            const pixelBasedSize = Math.max(Math.floor(pixelSize / 2), 2); // 像素处理使用更小的像素块，保留更多细节
            console.log(`🔧 像素处理像素大小: ${pixelBasedSize}`);
            filterChain = `[0:v]split[main][mosaic];[mosaic]crop=${w}:${h}:${x}:${y},scale=${Math.max(w/pixelBasedSize, 1)}:${Math.max(h/pixelBasedSize, 1)}:flags=neighbor,scale=${w}:${h}:flags=neighbor[mosaiced];[main][mosaiced]overlay=${x}:${y}[v]`;
        }

        console.log(`🔗 生成的马赛克滤镜链: ${filterChain}`);
        return filterChain;
    }

    /**
     * 构建时间条件表达式
     * @param {string} startTime - 开始时间 (HH:MM:SS)
     * @param {string} endTime - 结束时间 (HH:MM:SS)，null表示到视频结束
     */
    buildTimeCondition(startTime, endTime) {
        if (!startTime && !endTime) {
            return null; // 整个视频
        }

        const conditions = [];

        if (startTime) {
            const startSeconds = this.timeToSeconds(startTime);
            conditions.push(`gte(t,${startSeconds})`);
        }

        if (endTime) {
            const endSeconds = this.timeToSeconds(endTime);
            conditions.push(`lte(t,${endSeconds})`);
        }

        return conditions.length > 0 ? conditions.join('*') : null;
    }

    /**
     * 添加背景视频
     */
    async addBackgroundVideo(params, outputDir, progressCallback = null, workflowId = null) {
        const { inputFile, backgroundVideos, scaleMode = 'fill' } = params;
        
        if (!backgroundVideos || backgroundVideos.length === 0) {
            throw new Error('背景视频列表不能为空');
        }
        
        // 发送日志的辅助函数
        const sendLog = (message) => {
            console.log(message);
            if (progressCallback && workflowId) {
                progressCallback({
                    workflowId,
                    status: 'processing',
                    message
                });
            }
        };
        
        try {
            sendLog('开始添加背景视频处理...');
            
            // 解析输入音频文件路径
            const resolvedAudioPath = await this.findFileByName(inputFile);
            if (!resolvedAudioPath) {
                throw new Error(`找不到指定的音频文件: ${inputFile}`);
            }
            
            // 获取音频信息
            const audioInfo = await this.getAudioInfo(resolvedAudioPath);
            const audioDuration = audioInfo.duration;
            sendLog(`音频时长: ${audioDuration}秒`);
            
            // 随机选择背景视频
            const selectedVideoPath = backgroundVideos[Math.floor(Math.random() * backgroundVideos.length)];
            sendLog(`已选择背景视频: ${path.basename(selectedVideoPath)}`);
            
            // 解析背景视频路径
            let selectedVideo;
            if (path.isAbsolute(selectedVideoPath) && fs.existsSync(selectedVideoPath)) {
                selectedVideo = selectedVideoPath;
            } else {
                selectedVideo = await this.findFileByName(selectedVideoPath);
                if (!selectedVideo) {
                    throw new Error(`找不到指定的背景视频: ${selectedVideoPath}`);
                }
            }
            
            const outputFile = path.join(outputDir, `background_video_${Date.now()}.mp4`);
            
            // 构建滤镜链
            let videoFilter;
            if (scaleMode === 'fill') {
                videoFilter = 'scale=1920:1080:force_original_aspect_ratio=increase,crop=1920:1080';
            } else if (scaleMode === 'fit') {
                videoFilter = 'scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2:black';
            } else {
                videoFilter = 'scale=1920:1080';
            }
            
            return new Promise((resolve, reject) => {
                ffmpeg(selectedVideo)
                    .input(resolvedAudioPath)
                    .videoFilters(videoFilter)
                    .duration(audioDuration)
                    .outputOptions([
                        '-c:v', 'libx264',
                        '-c:a', 'aac',
                        '-map', '0:v:0',
                        '-map', '1:a:0',
                        '-shortest'
                    ])
                    .output(outputFile)
                    .on('progress', (progress) => {
                        if (progressCallback && workflowId) {
                            const percent = Math.min(Math.round(progress.percent || 0), 99);
                            progressCallback({
                                workflowId,
                                status: 'processing',
                                progress: percent,
                                message: `背景视频处理进度: ${percent}%`
                            });
                        }
                    })
                    .on('end', () => {
                        if (progressCallback && workflowId) {
                            progressCallback({
                                workflowId,
                                status: 'completed',
                                progress: 100,
                                message: '背景视频处理完成'
                            });
                        }
                        resolve({
                            type: 'backgroundVideo',
                            inputFiles: [selectedVideo, resolvedAudioPath],
                            outputFiles: [outputFile],
                            params
                        });
                    })
                    .on('error', reject)
                    .run();
            });
            
        } catch (error) {
            throw error;
        }
    }

    /**
     * 分割视频
     */
    async splitVideo(inputFile, params, outputDir, progressCallback = null, workflowId = null) {
        let { segments = [] } = params;
        const resolvedPath = await this.findFileByName(inputFile);
        if (!resolvedPath) {
            throw new Error(`找不到输入文件: ${inputFile}`);
        }
        
        // 处理固定长度分割模式
        if (segments.length === 1 && segments[0].mode === 'fixed_length') {
            const segmentLength = segments[0].segmentLength;
            if (!segmentLength || segmentLength <= 0) {
                throw new Error('分割长度必须大于0');
            }
            
            // 获取视频信息以计算总时长
            const videoInfo = await this.getVideoInfoInternal(resolvedPath);
            const totalDuration = videoInfo.duration;
            
            if (!totalDuration || totalDuration <= 0) {
                throw new Error('无法获取视频时长');
            }
            
            // 根据固定长度计算分割段
            segments = [];
            let currentStart = 0;
            let partIndex = 1;
            
            while (currentStart < totalDuration) {
                const currentEnd = Math.min(currentStart + segmentLength, totalDuration);
                segments.push({
                    startTime: this.formatTime(currentStart),
                    endTime: this.formatTime(currentEnd),
                    name: `part${partIndex.toString().padStart(2, '0')}`
                });
                currentStart = currentEnd;
                partIndex++;
            }
        }
        
        if (segments.length === 0) {
            throw new Error('分割段落不能为空');
        }
        
        // 发送日志的辅助函数
        const sendLog = (message) => {
            console.log(message);
            if (progressCallback && workflowId) {
                progressCallback({
                    workflowId,
                    status: 'processing',
                    message
                });
            }
        };
        
        try {
            sendLog('开始分割视频处理...');
            sendLog(`输入视频文件: ${path.basename(resolvedPath)}`);
            sendLog(`分割段数: ${segments.length}`);
            
            const outputFiles = [];
            const baseName = path.basename(resolvedPath, path.extname(resolvedPath));
            const extension = path.extname(resolvedPath);
            
            // 处理每个分割段
            for (let i = 0; i < segments.length; i++) {
                const segment = segments[i];
                const { startTime, endTime, name } = segment;
                
                const segmentName = name || `segment_${i + 1}`;
                const outputFile = path.join(outputDir, `${baseName}_${segmentName}_${Date.now()}${extension}`);
                
                sendLog(`正在处理分割段 ${i + 1}/${segments.length}: ${segmentName}`);
                
                await new Promise((resolve, reject) => {
                    const command = ffmpeg(resolvedPath)
                        .seekInput(startTime);
                    
                    // 只有当duration不为null时才设置duration
                    const duration = this.calculateDuration(startTime, endTime);
                    if (duration !== null) {
                        command.duration(duration);
                    }
                    
                    command.output(outputFile)
                        .on('progress', (progress) => {
                            if (progressCallback && workflowId) {
                                const totalProgress = Math.round(((i + (progress.percent || 0) / 100) / segments.length) * 100);
                                progressCallback({
                                    workflowId,
                                    status: 'processing',
                                    progress: totalProgress,
                                    message: `分割进度: 段落 ${i + 1}/${segments.length} - ${Math.round(progress.percent || 0)}%`
                                });
                            }
                        })
                        .on('end', () => {
                            sendLog(`分割段 ${i + 1} 完成: ${segmentName}`);
                            outputFiles.push(outputFile);
                            resolve();
                        })
                        .on('error', reject)
                        .run();
                });
            }
            
            if (progressCallback && workflowId) {
                progressCallback({
                    workflowId,
                    status: 'completed',
                    progress: 100,
                    message: '视频分割完成'
                });
            }
            
            return {
                type: 'split',
                inputFiles: [resolvedPath],
                outputFiles: outputFiles,
                params
            };
            
        } catch (error) {
            throw error;
        }
    }

    /**
     * 生成视频预览图
     */
    async generateVideoPreview(filePath, options = {}) {
        const { timestamp = 10, width = 640, height = 360 } = options;
        
        // 解析文件路径
        const resolvedPath = await this.findFileByName(filePath);
        if (!resolvedPath) {
            throw new Error(`找不到输入文件: ${filePath}`);
        }
        
        // 确保预览目录存在
        const previewDir = path.join(this.downloadDir, 'previews');
        await fs.ensureDir(previewDir);
        
        // 生成预览图文件名
        const baseName = path.basename(resolvedPath, path.extname(resolvedPath));
        const previewFileName = `preview_${baseName}_${timestamp}s_${width}x${height}.jpg`;
        const previewPath = path.join(previewDir, previewFileName);
        
        // 如果预览图已存在，直接返回
        if (await fs.pathExists(previewPath)) {
            return previewPath;
        }
        
        return new Promise((resolve, reject) => {
            ffmpeg(resolvedPath)
                .seekInput(timestamp)
                .frames(1)
                .size(`${width}x${height}`)
                .output(previewPath)
                .on('end', () => {
                    resolve(previewPath);
                })
                .on('error', (err) => {
                    console.error('生成视频预览图失败:', err);
                    reject(err);
                })
                .run();
        });
    }
}

module.exports = VideoProcessor;